package com.fau.wm.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.validation.ConstraintViolation;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.Hibernate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.fau.wm.entity.MedicalAdmin;
import com.fau.wm.entity.MedicalInStock;
import com.fau.wm.entity.MedicalLayerPosition;
import com.fau.wm.entity.MedicalMedicine;
import com.fau.wm.entity.MedicalMedicinePosition;
import com.fau.wm.entity.MedicalShelf;
import com.fau.wm.entity.MedicalShelfLayer;
import com.fau.wm.entity.MedicalWarehouse;
import com.fau.wm.service.IBaseDataManagerService;
import com.fau.wm.util.Page;
import com.fau.wm.util.ParamUtil;
import com.fau.wm.util.SerialNumUtil;
import com.fau.wm.util.ValidatorUtil;


@Service
@Transactional(readOnly = true)
public class BaseDataManagerService extends BaseService implements IBaseDataManagerService {

	@Override
	public Page findWarehouseByPage(MedicalWarehouse warehouse, Map<String, Object> map) {
		StringBuilder countSql = new StringBuilder("select count(*) from MedicalWarehouse where hospitalId = ? ");
		StringBuilder statusSql = new StringBuilder("from MedicalWarehouse where hospitalId = ? ");
		List<Object> objectList = new ArrayList<Object>();
		objectList.add(warehouse.getHospitalId());
		
		if(StringUtils.isNotBlank(warehouse.getName())){
			countSql.append("and name like ? ");
			statusSql.append("and name like ? ");
			objectList.add("%" +warehouse.getName()+ "%");
		}
		
		if(StringUtils.isNotBlank(warehouse.getCode())){
			countSql.append("and code=? ");
			statusSql.append("and code=? ");
			objectList.add(warehouse.getCode());
		}
		
		//排序
		String[] sortField = (String[]) map.get("sortField");
		String[] sortOrder = (String[]) map.get("sortOrder");
		if(StringUtils.isNotBlank(sortField[0]) && StringUtils.isNotBlank(sortOrder[0])) {
			statusSql.append("order by " + sortField[0] + " " + sortOrder[0] );
		}
		
		Page page = this.iBaseDao.getPage(ParamUtil.getInteger(map,"pageIndex",1),ParamUtil.getInteger(map, "pageSize", 20),
				map, countSql.toString(), statusSql.toString(), objectList);
		
		return page;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public Page findPositionByPage(MedicalLayerPosition layerPosition, Map<String, Object> map) {
		StringBuilder countSql = new StringBuilder("select count(*) from MedicalLayerPosition m where m.hospitalId=? ");
		StringBuilder statusSql = new StringBuilder("from MedicalLayerPosition m where m.hospitalId=? ");
		
		List<Object> objectList = new ArrayList<Object>();
		objectList.add(layerPosition.getHospitalId());
		
		if(StringUtils.isNotBlank(layerPosition.getWarehouseId())){
			countSql.append("and m.shelfLayer.shelf.warehouse.name like ? ");
			statusSql.append("and m.shelfLayer.shelf.warehouse.name like ? ");
			objectList.add("%"+layerPosition.getWarehouseId()+"%");
		}
		
		if(StringUtils.isNotBlank(layerPosition.getSerialNum())){
			countSql.append("and m.shelfLayer.shelf.warehouse.code = ? ");
			statusSql.append("and m.shelfLayer.shelf.warehouse.code = ? ");
			objectList.add(layerPosition.getSerialNum());
		}
		
		if(StringUtils.isNotBlank(layerPosition.getShelfNum())){
			countSql.append("and m.shelfLayer.shelf.shelfNum = ? ");
			statusSql.append("and m.shelfLayer.shelf.shelfNum = ? ");
			objectList.add(layerPosition.getShelfNum());
		}
		
		if(StringUtils.isNotBlank(layerPosition.getLayer())){
			countSql.append("and m.shelfLayer.layerNum = ? ");
			statusSql.append("and m.shelfLayer.layerNum = ? ");
			objectList.add(layerPosition.getLayer());
		}
		
		if(StringUtils.isNotBlank(layerPosition.getPositionNum())){
			countSql.append("and m.positionNum = ? ");
			statusSql.append("and m.positionNum = ? ");
			objectList.add(layerPosition.getPositionNum());
		}
		
		//排序
		String[] sortField = (String[]) map.get("sortField");
		String[] sortOrder = (String[]) map.get("sortOrder");
		if(StringUtils.isNotBlank(sortField[0]) && StringUtils.isNotBlank(sortOrder[0])) {
			statusSql.append("order by m." + sortField[0] + " " + sortOrder[0] );
		} else {
			statusSql.append("order by m.updateTime desc ");
		}
		
		Page page = this.iBaseDao.getPage(ParamUtil.getInteger(map,"pageIndex",1),ParamUtil.getInteger(map, "pageSize", 20),
				map, countSql.toString(), statusSql.toString(), objectList);
		
		List<MedicalLayerPosition> layerPositions = (List<MedicalLayerPosition>) page.getResult();
		
		for (MedicalLayerPosition medicalLayerPosition : layerPositions) {
			Hibernate.initialize(medicalLayerPosition.getMedicineSets());
		}
		
		page.setResult(layerPositions);
		return page;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public List<MedicalWarehouse> findWarehouseByHospital(String hospitalId) {
		List<MedicalWarehouse> list = this.iBaseDao.getBySql("from MedicalWarehouse m where m.hospitalId=? ", null, hospitalId);
		return list;
	}

	@Override
	@Transactional(readOnly = false, propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
	public boolean saveWarehouse(MedicalWarehouse warehouse, MedicalAdmin admin) {
		Set<ConstraintViolation<Object>> errorInfo = ValidatorUtil.validateObj(warehouse);
		if(errorInfo.size()>0){
			return false;
		}else{
			warehouse.setCode(SerialNumUtil.code());
			warehouse.setHospitalId(admin.getEnterpriseId());
			return this.iBaseDao.saveObject(warehouse);
		}
	}
	
	@Override
	@Transactional(readOnly = false, propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
	public void editWarehouse(MedicalWarehouse warehouse) {
		MedicalWarehouse mw = (MedicalWarehouse) this.iBaseDao.getObject(MedicalWarehouse.class, warehouse.getId());
		mw.setName(warehouse.getName());
		mw.setArea(warehouse.getArea());
		mw.setAddress(warehouse.getAddress());
		this.iBaseDao.saveObject(mw);
	}
	
	@Override
	@Transactional(readOnly = false, propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
	public boolean saveLayerPosition(MedicalLayerPosition layerPosition, MedicalAdmin admin) {
		Set<ConstraintViolation<Object>> errorInfo = ValidatorUtil.validateObj(layerPosition);
		if(errorInfo.size()>0){
			return false;
		}else{
			MedicalWarehouse warehouse = (MedicalWarehouse) this.iBaseDao.getObject(MedicalWarehouse.class, layerPosition.getWarehouseId());
			
			// 判断货架是否已经存在
			MedicalShelf sf = (MedicalShelf) this.iBaseDao.getObjectByHql("from MedicalShelf m where m.warehouse.id=? and m.shelfNum=? ",
					layerPosition.getWarehouseId(),layerPosition.getShelfNum().trim());
			if(null == sf) {
				sf = new MedicalShelf(layerPosition.getShelfNum().trim(),warehouse);
				this.iBaseDao.saveObject(sf);
			}
			
			// 判断货架的层是否已经存在
			MedicalShelfLayer shelfLayer = (MedicalShelfLayer) this.iBaseDao.getObjectByHql("from MedicalShelfLayer m where m.shelf.id=? and m.layerNum=? ", 
					sf.getId(),layerPosition.getLayer());
			if(null == shelfLayer) {
				shelfLayer = new MedicalShelfLayer(layerPosition.getLayer().trim(),sf);
				this.iBaseDao.saveObject(shelfLayer);
			}
			
			// 判断该层的位是否已经存在
			MedicalLayerPosition position = (MedicalLayerPosition) this.iBaseDao.getObjectByHql("from MedicalLayerPosition m where m.shelfLayer.id=? and m.positionNum=? ",
					shelfLayer.getId(),layerPosition.getPositionNum().trim());
			if(null == position) {
				position = new MedicalLayerPosition(layerPosition.getPositionNum().trim(),shelfLayer);
				position.setHospitalId(admin.getEnterpriseId());
				position.setOperator(layerPosition.getOperator());
				this.iBaseDao.saveObject(position);
				String[] relationMedicals = layerPosition.getMedicals().split(",");
				for (String rm : relationMedicals) {
					MedicalMedicinePosition mp = new MedicalMedicinePosition();
					MedicalMedicine medicine = (MedicalMedicine) this.iBaseDao.getObject(MedicalMedicine.class, rm);
					mp.setMedicine(medicine);
					mp.setLayerPosition(position);
					this.iBaseDao.saveObject(mp);
				}
			}else {
				// 如果储位已经存在则不能重复添加
				return false;
			}
			
			return true;
		}
		
	}
	
	@Override
	@Transactional(readOnly = false, propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
	public boolean editLayerPosition(MedicalLayerPosition layerPosition) {
		MedicalWarehouse warehouse = (MedicalWarehouse) this.iBaseDao.getObject(MedicalWarehouse.class, layerPosition.getWarehouseId());
		
		// 判断货架是否已经存在
		MedicalShelf sf = (MedicalShelf) this.iBaseDao.getObjectByHql("from MedicalShelf m where m.warehouse.id=? and m.shelfNum=? ",
				layerPosition.getWarehouseId(),layerPosition.getShelfNum().trim());
		if (null == sf) {
			sf = new MedicalShelf(layerPosition.getShelfNum().trim(),warehouse);
			this.iBaseDao.saveObject(sf);
		}
		
		// 判断货架的层是否已经存在
		MedicalShelfLayer shelfLayer = (MedicalShelfLayer) this.iBaseDao.getObjectByHql("from MedicalShelfLayer m where m.shelf.id=? and m.layerNum=? ", 
				sf.getId(),layerPosition.getLayer().trim());
		if (null == shelfLayer) {
			shelfLayer = new MedicalShelfLayer(layerPosition.getLayer().trim(),sf);
			this.iBaseDao.saveObject(shelfLayer);
		}
		
		// 判断该层的这个位置是否已经存在
		int count = this.iBaseDao.getIntCount("select count(*) from MedicalLayerPosition m where m.shelfLayer.id=? and m.positionNum=? "
				,shelfLayer.getId(),layerPosition.getPositionNum().trim());
		
		if ( count > 1 ){
			return false;
		} else {
			// 更新
			MedicalLayerPosition position = (MedicalLayerPosition) this.iBaseDao.getObject(MedicalLayerPosition.class, layerPosition.getId());
			
			if (StringUtils.isNotBlank(layerPosition.getMedicals())) {
				// 先清空该位置与药品的关联
				this.iBaseDao.updateHql("delete from MedicalMedicinePosition m where m.layerPosition.id=? ", position.getId());
				
				// 保存新的关联
				String[] newMedicineSet = layerPosition.getMedicals().split(",");
				for (String rm : newMedicineSet) {
					MedicalMedicinePosition mp = new MedicalMedicinePosition();
					MedicalMedicine medicine = (MedicalMedicine) this.iBaseDao.getObject(MedicalMedicine.class, rm);
					mp.setMedicine(medicine);
					mp.setLayerPosition(position);
					this.iBaseDao.saveObject(mp);
				}
			} else{
				this.iBaseDao.updateHql("delete from MedicalMedicinePosition m where m.layerPosition.id=? ", position.getId());
			}
			
			position.setPositionNum(layerPosition.getPositionNum().trim());
			position.setShelfLayer(shelfLayer);
			position.setOperator(layerPosition.getOperator());
			
			this.iBaseDao.saveObject(position);
		}
		
		return true;
	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional(readOnly = false, propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
	public boolean deleteWarehouse(MedicalWarehouse warehouse) {
		String[] ids = warehouse.getId().split("-");
		for (String id : ids) {
			List<MedicalInStock> list = this.iBaseDao.getBySql("from MedicalInStock a where a.warehouse.id=? ", null, id);
			if(list.size() > 0){
				return false;
			}else{
				this.iBaseDao.updateHql("delete from MedicalWarehouse a where a.id=? ", id);
			}
		}
		return true;
	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional(readOnly = false, propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
	public boolean deleteLayerPosition(MedicalLayerPosition layerPosition) {
		String[] ids = layerPosition.getId().split("-");
		for (String lpid : ids) {
			List<MedicalMedicinePosition> list = this.iBaseDao.getBySql("from MedicalMedicinePosition m where m.layerPosition.id=? ", null, lpid);
			if(list.size() > 0){
				return false;
			}else{
				this.iBaseDao.updateHql("delete from MedicalLayerPosition a where a.id=? ", lpid);
			}
		}
		return true;
	}

}
